package com.citic.topview.common.json;

import java.io.IOException;
import java.util.TimeZone;

import javax.servlet.ServletResponse;

import org.apache.commons.text.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;

public class JsonMapper extends ObjectMapper {

	private static final long serialVersionUID = 1L;
	
	private Logger logger = LoggerFactory.getLogger(JsonMapper.class);

	private static JsonMapper mapper;
	
	public JsonMapper() {

	}
	
	public JsonMapper(Include include) {
		// 设置输出时包含属性的风格
		if (include != null) {
			this.setSerializationInclusion(include);
		}
		// 允许单引号、允许不带引号的字段名称
		this.enableSimple();
		// 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
		this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        // 空值处理为空串
		this.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>(){
			@Override
			public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
				jgen.writeString("");
			}
        });
		// 进行HTML解码。
		this.registerModule(new SimpleModule().addSerializer(String.class, new JsonSerializer<String>(){
			@Override
			public void serialize(String value, JsonGenerator jgen,
					SerializerProvider provider) throws IOException,
					JsonProcessingException {
				jgen.writeString(StringEscapeUtils.unescapeHtml4(value));
			}
        }));
		// 设置时区
		this.setTimeZone(TimeZone.getDefault());//getTimeZone("GMT+8:00")
	}

	public static JsonMapper getInstance() {
		if (mapper == null){
			mapper = new JsonMapper().enableSimple();
		}
		return mapper;
	}
	
	public JsonMapper enableSimple() {
		this.configure(Feature.ALLOW_SINGLE_QUOTES, true);
		this.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
		return this;
	}
	
	public static String toJsonString(Object object){
		return JsonMapper.getInstance().toJson(object);
	}

	public String toJson(Object object) {
		try {
			return this.writeValueAsString(object);
		} catch (IOException e) {
			logger.warn("write to json string error:" + object, e);
			return null;
		}
	}

	public static void renderJson(final Object data, final ServletResponse response) {
		nonEmptyMapper().renderJsonToResponse(data, response);
	}
	
	private void renderJsonToResponse(Object data, ServletResponse response) {
		initResponseHeader(response);
		try {
			JsonMapper.getInstance().writeValue(response.getWriter(), data);
		} catch (IOException e) {
			logger.warn("write to json response error:" + data.toString(), e);
			throw new IllegalArgumentException(e);
		}
	}

	private static final String DEFAULT_ENCODING = "UTF-8";
	public static final String JSON_TYPE = "application/json";
	
	private void initResponseHeader(ServletResponse response) {
		String contentType = JSON_TYPE + ";charset=" + DEFAULT_ENCODING;
		response.setContentType(contentType);		
	}

	// 创建只输出非Null且非Empty(如List.isEmpty)的属性到Json字符串的Mapper,建议在外部接口中使用.
	public static JsonMapper nonEmptyMapper() {
		return new JsonMapper(Include.NON_EMPTY);
	}
}
